home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / daemons / nfs / nfs-serv.2be / nfs-serv / nfs-server-2.2beta16 / nfsd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-28  |  24.3 KB  |  1,040 lines

  1. /*
  2.  * nfsd        This program handles RPC "NFS" data requests.
  3.  *
  4.  * Usage:    [rpc.]nfsd [-Fhnprv] [-f authfile] [-d debugfac]
  5.  *
  6.  * Authors:    Mark A. Shand, May 1988
  7.  *        Donald J. Becker, <becker@super.org>
  8.  *        Rick Sladkey, <jrs@world.std.com>
  9.  *        Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  10.  *        Eric Kasten, <tigger@tigger.cl.msu.edu>
  11.  *        Olaf Kirch, <okir@monad.swb.de>
  12.  *
  13.  *        Copyright 1988 Mark A. Shand
  14.  *        This software maybe be used for any purpose provided
  15.  *        the above copyright notice is retained.  It is supplied
  16.  *        as is, with no warranty expressed or implied.
  17.  */
  18.  
  19. #include "nfsd.h"
  20. #include <rpc/pmap_clnt.h>
  21. #include "getopt.h"
  22. #include "fsusage.h"
  23. #include "rpcmisc.h"
  24. #ifdef __linux__ /* XXX - MvS: for UNIX sockets. */
  25. #  include <sys/un.h>
  26. #endif
  27.  
  28. #define MULTIPLE_SERVERS
  29.  
  30. /* Flags for auth_fh */
  31. #define CHK_READ    0
  32. #define CHK_WRITE    1
  33. #define CHK_NOACCESS    2
  34.  
  35. /* Make larger reads possible. Without crashing the machine :-) */
  36. #undef NFS_MAXDATA
  37. #define NFS_MAXDATA    (16 * 1024)
  38.  
  39. static char iobuf[NFS_MAXDATA];
  40. static char pathbuf[NFS_MAXPATHLEN + 1];
  41. static char pathbuf_1[NFS_MAXPATHLEN + 1];
  42.  
  43. extern char version[];
  44. static char *program_name;
  45. static struct option longopts[] =
  46. {
  47.     { "debug", 1, 0, 'd' },
  48.     { "foreground", 0, 0, 'F' },
  49.     { "exports-file", 1, 0, 'f' },
  50.     { "help", 0, 0, 'h' },
  51.     { "allow-non-root", 0, 0, 'n' },
  52.     { "port", 1, 0, 'P' },
  53.     { "promiscuous", 0, 0, 'p' },
  54.     { "re-export", 0, 0, 'r', },
  55.     { "synchronous-writes", 0, 0, 's' },
  56.     { "no-spoof-trace", 0, 0, 't' },
  57.     { "version", 0, 0, 'v' },
  58.     { NULL, 0, 0, 0 }
  59. };
  60. nfs_client        *nfsclient = NULL;    /* the current client */
  61. nfs_mount        *nfsmount = NULL;    /* the current mount point */
  62. int            need_reinit = 0;    /* SIGHUP handling */
  63. int            need_flush = 0;        /* flush fh cache */
  64. int            read_only = 0;        /* Global ro forced */
  65.  
  66. static _PRO (nfsstat build_path, (struct svc_req *rqstp, char *buf,
  67.                 diropargs * da, int flags)        );
  68. static _PRO (fhcache *auth_fh, (struct svc_req *rqstp, nfs_fh *fh, 
  69.                 nfsstat *statp, int flags)        );
  70. static _PRO (void usage, (FILE *, int)                    );
  71.  
  72.  
  73. #ifdef CALL_PROFILING
  74. extern _PRO (void dump_stats, (int sig)                    );
  75. #endif
  76.  
  77. /*
  78.  * auth_fh
  79.  *
  80.  * This function authenticates the file handle provided by the client.
  81.  * It also takes care of caching the client and mount point structures
  82.  * in the fh cache entry, although this may not be a huge benefit.
  83.  */
  84. static fhcache *auth_fh(rqstp, fh, statp, flags)
  85. struct svc_req *rqstp;
  86. nfs_fh *fh;
  87. nfsstat *statp;
  88. int flags;
  89. {
  90.     static int total = 0, cached = 0;
  91.     fhcache *fhc;
  92.  
  93.     /* Try to map FH. If not cached, reconstruct path with root priv */
  94.     if ((fhc = fh_find((svc_fh *)fh, FHFIND_FEXISTS)) == NULL) {
  95.         *statp = NFSERR_STALE;
  96.         return NULL;
  97.     }
  98.  
  99.     /* Try to retrieve last client who accessed this fh */
  100.     if (nfsclient == NULL) {
  101.         struct in_addr    caddr;
  102.  
  103.         caddr = svc_getcaller(rqstp->rq_xprt)->sin_addr;
  104.         if (fhc->last_clnt != NULL &&
  105.             fhc->last_clnt->clnt_addr.s_addr == caddr.s_addr) {
  106.             nfsclient = fhc->last_clnt;
  107.         } else if ((nfsclient = auth_clnt(rqstp)) == NULL) {
  108.             *statp = NFSERR_ACCES;
  109.             return NULL;
  110.         }
  111.     }
  112.  
  113.     if (fhc->last_clnt == nfsclient) {
  114.         nfsmount = fhc->last_mount; /* get cached mount point */
  115.         cached++;
  116.     } else {
  117.         nfsmount = auth_path(nfsclient, rqstp, fhc->path);
  118.         if (nfsmount == NULL) {
  119.             *statp = NFSERR_ACCES;
  120.             return NULL;
  121.         }
  122.         fhc->last_clnt = nfsclient;
  123.         fhc->last_mount = nfsmount;
  124.     }
  125.     total++;
  126.     /*
  127.     if (total % 1000 == 0)
  128.         dprintf(D_FHCACHE, "ratio of cached client ptrs %4.1f%%\n",
  129.             100 * (double) cached / total);
  130.      */
  131.  
  132.     if (nfsmount->o.noaccess &&
  133.         ((flags & CHK_NOACCESS) || strcmp(nfsmount->path, fhc->path))) {
  134.         struct in_addr    addr = svc_getcaller(rqstp->rq_xprt)->sin_addr;
  135.         dprintf(L_WARNING, "client %s tried to access %s (noaccess)\n",
  136.                 inet_ntoa(addr), fhc->path);
  137.         *statp = NFSERR_ACCES;
  138.         return NULL;
  139.     }
  140.  
  141.     if ((flags & CHK_WRITE) && (nfsmount->o.read_only || read_only)) {
  142.         *statp = NFSERR_ROFS;
  143.         return NULL;
  144.     }
  145.  
  146.     auth_user(nfsmount, rqstp);
  147.  
  148.     *statp = NFS_OK;
  149.     return fhc;
  150. }
  151.  
  152. static inline nfsstat build_path(rqstp, buf, da, flags)
  153. struct svc_req *rqstp;
  154. char *buf;
  155. diropargs *da;
  156. int flags;
  157. {
  158.     fhcache *fhc;
  159.     nfsstat status;
  160.     char *path = buf, *sp;
  161.  
  162.     if ((fhc = auth_fh(rqstp, &(da->dir), &status, flags)) == NULL)
  163.         return status;
  164.  
  165.     sp = fhc->path;
  166.  
  167.     while (*sp)        /* strcpy(buf, fhc->path); */
  168.         *buf++ = *sp++;
  169.     *buf++ = '/';        /* strcat(buf, "/");  */
  170.     sp = da->name;
  171.     while (*sp)        /* strcat(pathbuf, argp->where.name); */
  172.         *buf++ = *sp++;
  173.     *buf = '\0';
  174.  
  175.     if ((nfsmount = auth_path(nfsclient, rqstp, path)) == NULL) {
  176.         return NFSERR_ACCES;
  177.     }
  178.     auth_user(nfsmount, rqstp);
  179.  
  180.     return (NFS_OK);
  181. }
  182.  
  183. /*
  184.  * The "wrappers" of the following functions came from `rpcgen -l nfs_prot.x`.
  185.  * This normally generates the client routines, but it provides nice
  186.  * prototypes for the server routines also.
  187.  */
  188. int nfsd_nfsproc_null_2(argp, rqstp)
  189. void *argp;
  190. struct svc_req    *rqstp;
  191. {
  192.     return (0);
  193. }
  194.  
  195. int nfsd_nfsproc_getattr_2(argp, rqstp)
  196. nfs_fh *argp;
  197. struct svc_req    *rqstp;
  198. {
  199.     nfsstat status;
  200.     fhcache *fhc;
  201.  
  202.     fhc = auth_fh(rqstp, argp, &status, CHK_READ);
  203.     if (fhc == NULL)
  204.         return status;
  205.  
  206.     return (fhc_getattr(fhc, &result.attrstat.attrstat_u.attributes,
  207.                         NULL, rqstp));
  208. }
  209.  
  210. int nfsd_nfsproc_setattr_2(argp, rqstp)
  211. sattrargs *argp;
  212. struct svc_req    *rqstp;
  213. {
  214.     nfsstat status;
  215.     fhcache *fhc;
  216.     char *path;
  217.     struct stat buf;
  218.  
  219.     fhc = auth_fh(rqstp, &(argp->file), &status, CHK_WRITE | CHK_NOACCESS);
  220.     if (fhc == NULL)
  221.         return status;
  222.     path = fhc->path;
  223.  
  224.     errno = 0;
  225.     /* Stat the file first and only change fields that are different. */
  226.     if (lstat(path, &buf) < 0)
  227.         goto failure;
  228.  
  229.     status = setattr(path, &argp->attributes, &buf, rqstp, SATTR_ALL);
  230.     if (status != NFS_OK)
  231.         return status;
  232.     return (fhc_getattr(fhc, &(result.attrstat.attrstat_u.attributes),
  233.                         &buf, rqstp));
  234.  
  235. failure:
  236.     return (nfs_errno());
  237. }
  238.  
  239. int nfsd_nfsproc_root_2(argp, rqstp)
  240. void *argp;
  241. struct svc_req    *rqstp;
  242. {
  243.     return (0);
  244. }
  245.  
  246. int nfsd_nfsproc_lookup_2(argp, rqstp)
  247. diropargs *argp;
  248. struct svc_req    *rqstp;
  249. {
  250.     diropokres    *dp = &result.diropres.diropres_u.diropres;
  251.     fhcache        *fhc;
  252.     nfsstat        status;
  253.     struct stat    sbuf;
  254.     struct stat    *sbp = &sbuf;
  255.  
  256.     /* Must authenticate dir FH to set fsuid/fsgid. Thanks to
  257.      * Stig Venaas for his bug report.
  258.      */
  259.     if (auth_fh(rqstp, &(argp->dir), &status, CHK_READ) == NULL)
  260.         return status;
  261.  
  262.     status = fh_compose(argp, &(dp->file), &sbp, -1, -1);
  263.     if (status != NFS_OK)
  264.         return status;
  265.  
  266.     fhc = auth_fh(rqstp, &(dp->file), &status, CHK_READ);
  267.     if (fhc == NULL)
  268.         return status;
  269.  
  270.     status = fhc_getattr(fhc, &(dp->attributes), sbp, rqstp);
  271.     if (status == NFS_OK)
  272.         dprintf(D_CALL, "\tnew_fh = %s\n", fh_pr(&(dp->file)));
  273.  
  274.     return (status);
  275. }
  276.  
  277. int nfsd_nfsproc_readlink_2(argp, rqstp)
  278. nfs_fh *argp;
  279. struct svc_req    *rqstp;
  280. {
  281.     nfsstat status;
  282.     fhcache *fhc;
  283.     char *path;
  284.     int cc;
  285.  
  286.     fhc = auth_fh(rqstp, argp, &status, CHK_READ | CHK_NOACCESS);
  287.     if (fhc == NULL)
  288.         return status;
  289.     path = fhc->path;
  290.  
  291.     errno = 0;
  292.     if ((cc = readlink(path, pathbuf, NFS_MAXPATHLEN)) < 0) {
  293.         dprintf(D_CALL, " >>> %s\n", strerror(errno));
  294.         return (nfs_errno());
  295.     }
  296.     status = NFS_OK;
  297.     pathbuf[cc] = '\0';    /* readlink() doesn't null terminate!! */
  298.     result.readlinkres.readlinkres_u.data = pathbuf;
  299.  
  300.     if (nfsmount->o.link_relative && pathbuf[0] == '/') {
  301.         /*
  302.          * We've got an absolute (locally) pathname, and we should
  303.          * translate to a relative pathname for the client.  We do
  304.          * this by prepending the correct number of "../"es to the
  305.          * path. This cannot work if the client does not mount the
  306.          * specified subtree of the filesystem.
  307.          */
  308.         int slash_cnt = 0;
  309.         char *p, *q;
  310.  
  311.         /* Count how many directories down we are. */
  312.         for (p = path + 1; *p != '\0'; p++)
  313.             if (*p == '/')
  314.                 slash_cnt++;
  315.  
  316.         /*
  317.          * Ok, now we are finished with the orginal file `path'
  318.          * and will only deal with the link target.
  319.          */
  320.         p = &pathbuf[cc];    /* Point to the end and calculate */
  321.         if (slash_cnt == 0)
  322.             q = p + 1;    /* the extra space taken by a    */
  323.         else            /* prepended '.'          */
  324.             q = p + 3 * slash_cnt - 1;    /* or '../.../..' */
  325.  
  326.         if (q >= pathbuf + NFS_MAXPATHLEN) {
  327.             dprintf(D_CALL, " [[NAME TOO LONG!!]]\n");
  328.             return (NFSERR_NAMETOOLONG);
  329.         } else {
  330.             /* Add some space at the beginning of the string. */
  331.             while (p >= pathbuf)
  332.                 *q-- = *p--;
  333.  
  334.             if (slash_cnt == 0)
  335.                 pathbuf[0] = '.';
  336.             else {
  337.                 /*
  338.                  * This overwrites the leading '/' on the
  339.                  * last iteration.
  340.                  */
  341.                 for (p = pathbuf; slash_cnt > 0; slash_cnt--) {
  342.                     *p++ = '.';
  343.                     *p++ = '.';
  344.                     *p++ = '/';
  345.                 }
  346.             }
  347.         }
  348.     }
  349.     dprintf(D_CALL, " %s\n", result.readlinkres.readlinkres_u.data);
  350.     return (NFS_OK);
  351. }
  352.  
  353. int nfsd_nfsproc_read_2(argp, rqstp)
  354. readargs *argp;
  355. struct svc_req    *rqstp;
  356. {
  357.     nfsstat status;
  358.     fhcache *fhc;
  359.     readokres *res = &result.readres.readres_u.reply;
  360.     int    fd, len;
  361.  
  362.     fhc = auth_fh(rqstp, &(argp->file), &status, CHK_READ | CHK_NOACCESS);
  363.     if (fhc == NULL)
  364.         return status;
  365.  
  366.     if ((fd = fh_fd(fhc, &status, O_RDONLY)) < 0) {
  367.         return ((int) status);
  368.     }
  369.     errno = 0;
  370.     (void) lseek(fd, (long) argp->offset, L_SET);
  371.     if (!errno) {
  372.         res->data.data_val = iobuf;
  373.         if ((len = argp->count) > NFS_MAXDATA)
  374.             len = NFS_MAXDATA;
  375.         res->data.data_len = read(fd, iobuf, len);
  376.     }
  377.     fd_inactive(fd);
  378.     if (errno)
  379.         return (nfs_errno());
  380.     return (fhc_getattr(fhc, &(res->attributes), NULL, rqstp));
  381. }
  382.  
  383. int nfsd_nfsproc_writecache_2(argp, rqstp)
  384. void *argp;
  385. struct svc_req    *rqstp;
  386. {
  387.     return (0);
  388. }
  389.  
  390. int nfsd_nfsproc_write_2(argp, rqstp)
  391. writeargs *argp;
  392. struct svc_req    *rqstp;
  393. {
  394.     nfsstat status;
  395.     fhcache *fhc;
  396.     int fd;
  397.  
  398.     fhc = auth_fh(rqstp, &(argp->file), &status, CHK_WRITE | CHK_NOACCESS);
  399.     if (fhc == NULL)
  400.         return status;
  401.  
  402.     if ((fd = fh_fd(fhc, &status, O_WRONLY)) < 0) {
  403.         return ((int) status);
  404.     }
  405.     errno = 0;
  406.     (void) lseek(fd, (long) argp->offset, L_SET);
  407.     if (errno == 0) {    /* We should never fail. */
  408.         if (write(fd, argp->data.data_val, argp->data.data_len) !=
  409.             argp->data.data_len) {
  410.             dprintf(D_CALL, " Write failure, errno is %d.\n", errno);
  411.         }
  412.     }
  413.     fd_inactive(fd);
  414.     if (errno)
  415.         return (nfs_errno());
  416.     return (fhc_getattr(fhc, &(result.attrstat.attrstat_u.attributes),
  417.                             NULL, rqstp));
  418. }
  419.  
  420. /* This used to be O_RDWR, but O_WRONLY is correct */
  421. #define CREATE_OMODE O_WRONLY
  422.  
  423. int nfsd_nfsproc_create_2(argp, rqstp)
  424. createargs *argp;
  425. struct svc_req    *rqstp;
  426. {
  427.     nfsstat status;
  428.     diropokres *res;
  429.     int tmpfd, flags;
  430.     struct stat sbuf;
  431.     struct stat *sbp = &sbuf;
  432.     int is_borc;
  433.     int dev;
  434.     int exists;
  435. #ifdef __linux__ /* XXX - MvS: to create UNIX sockets. */
  436.     struct sockaddr_un sa;
  437.     int s;
  438. #endif
  439.  
  440.     /* We get the access status and file handle here, but check the
  441.      * status later. This is to let an "echo >/dev/null" from SunOS
  442.      * clients succeed on RO-filesystems.
  443.      */
  444.     status = build_path(rqstp, pathbuf, &argp->where,
  445.                     CHK_WRITE | CHK_NOACCESS);
  446.     if (status != NFS_OK && status != NFSERR_ROFS)
  447.         return ((int) status);
  448.     dprintf(D_CALL, "\tfullpath='%s'\n", pathbuf);
  449.     errno = 0;
  450.  
  451.     exists = lstat(pathbuf, &sbuf) == 0;
  452.  
  453.     /* Compensate for a really bizarre bug in SunOS derived clients. */
  454.     if ((argp->attributes.mode & S_IFMT) == 0) {
  455.         argp->attributes.mode |= exists
  456.             ? (sbuf.st_mode & S_IFMT) : S_IFREG;
  457.         if (!S_ISREG(argp->attributes.mode)) {
  458.             /* This branch is excuted only if the file exists
  459.              * and is a special file. */
  460.             status = NFS_OK;
  461.             argp->attributes.size = (major(sbuf.st_rdev) << 8)
  462.                     | minor(sbuf.st_rdev);
  463.         }
  464.     }
  465.     if (status != NFS_OK)
  466.         return ((int)status);
  467.  
  468.     /* First handle any unusual file-types. */
  469.     if (!S_ISREG(argp->attributes.mode)) {
  470.         if (S_ISBLK(argp->attributes.mode)
  471.             || S_ISCHR(argp->attributes.mode)) {
  472.             is_borc = 1;
  473.             /* This is probably better than just using
  474.                the size field by itself, but not by much. */
  475.             dev = makedev(((argp->attributes.size >> 8) & 0xff),
  476.                 (argp->attributes.size & 0xff));
  477.  
  478.             /* MvS: Some clients use chardev 0xFFFF for a FIFO. */
  479.             if (S_ISCHR(argp->attributes.mode) && dev == 0xFFFF) {
  480.                 is_borc = 0;
  481.                 dev = 0;
  482.                 argp->attributes.mode &= ~S_IFMT;
  483.                 argp->attributes.mode |= S_IFIFO;
  484.             }
  485.         }
  486.         else {
  487.             is_borc = 0;
  488.             dev = 0;
  489.         }
  490.         /* mknod will fail for EEXIST, we'll let it succeed. */
  491.         if (!exists) {
  492. #ifdef __linux__ /* XXX - MvS */
  493.             /* Can't make UNIX sockets with mknod. */
  494.             if (S_ISSOCK(argp->attributes.mode)) {
  495.               if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
  496.                       return(nfs_errno());
  497.               sa.sun_family = AF_UNIX;
  498.               strncpy(sa.sun_path, pathbuf, UNIX_PATH_MAX);
  499.               if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
  500.                 (void) close(s);
  501.                     return(nfs_errno());
  502.               }
  503.               (void) close(s);
  504.             } else
  505. #endif
  506.             if (mknod(pathbuf, argp->attributes.mode, dev) < 0)
  507.                 return (nfs_errno());
  508.             if (stat(pathbuf, &sbuf) < 0)
  509.                 return (nfs_errno());
  510.         }
  511.         else {
  512.             /* But make sure it's the same kind of special file. */
  513.             if ((argp->attributes.mode & S_IFMT)
  514.                 != (sbuf.st_mode & S_IFMT))
  515.                 return (NFSERR_EXIST);
  516.             /* And that the major and minor numbers agree. */
  517.             if (is_borc && dev != sbuf.st_rdev)
  518.                 return (NFSERR_EXIST);
  519.         }
  520.         tmpfd = -1;
  521.     }
  522.     else {
  523.         flags = (argp->attributes.size == 0 ?
  524.             CREATE_OMODE | O_CREAT | O_TRUNC :
  525.             CREATE_OMODE | O_CREAT);
  526.         tmpfd = path_open(pathbuf, flags, 
  527.                 argp->attributes.mode & ~S_IFMT);
  528.         if (tmpfd < 0)
  529.             goto failure;
  530.         (void) fstat(tmpfd, &sbuf);
  531.     }
  532.  
  533.     /* creat() is equivalent to open(..., O_CREAT|O_TRUNC|O_WRONLY) */
  534.     if (!exists) {
  535. #ifndef ALLOW_SGIDDIR
  536.         argp->attributes.gid = -1;
  537. #endif
  538.         /* Note: we ignore the size attribute because some clients
  539.          * create files with mode 0444. Since the file didn't exist
  540.          * previously, its length is zero anyway.
  541.          */
  542.         status = setattr(pathbuf, &argp->attributes, &sbuf,
  543.                     rqstp, SATTR_ALL & ~SATTR_SIZE);
  544.     } else {
  545.         status = setattr(pathbuf, &argp->attributes, &sbuf,
  546.                     rqstp, SATTR_SIZE);
  547.     }
  548.     if (status != NFS_OK)
  549.         return status;
  550.  
  551.     res = &result.diropres.diropres_u.diropres;
  552.     status = fh_compose(&(argp->where), &(res->file), &sbp,
  553.         tmpfd, CREATE_OMODE);
  554.     if (status != NFS_OK)
  555.         goto failure;
  556.     status = fh_getattr(&(res->file), &(res->attributes), sbp, rqstp);
  557.     if (status != NFS_OK) {
  558.         tmpfd = -1;    /* fd already stored in fh cache */
  559.         goto failure;
  560.     }
  561.     dprintf(D_CALL, "\tnew_fh = %s\n", fh_pr(&(res->file)));
  562.     return (status);
  563.  
  564. failure:
  565.     dprintf(D_CALL, "\tcreate failed -- errno returned=%d.\n", errno);
  566.     if (tmpfd != -1)
  567.         close(tmpfd);
  568.     return (errno? nfs_errno(): status);
  569. }
  570.  
  571. #undef CREATE_OMODE
  572.  
  573. int nfsd_nfsproc_remove_2(argp, rqstp)
  574. diropargs *argp;
  575. struct svc_req    *rqstp;
  576. {
  577.     nfsstat status;
  578.  
  579.     status = build_path(rqstp, pathbuf, argp, CHK_WRITE | CHK_NOACCESS);
  580.     if (status != NFS_OK)
  581.         return ((int) status);
  582.  
  583.     dprintf(D_CALL, "\tfullpath='%s'\n", pathbuf);
  584.  
  585.     /* Remove the file handle from our cache. */
  586.     fh_remove(pathbuf);
  587.  
  588.     if (unlink(pathbuf) != 0)
  589.         return (nfs_errno());
  590.     else
  591.         return (NFS_OK);
  592. }
  593.  
  594. int nfsd_nfsproc_rename_2(argp, rqstp)
  595. renameargs *argp;
  596. struct svc_req    *rqstp;
  597. {
  598.     nfsstat status;
  599.  
  600.     status = build_path(rqstp, pathbuf, &argp->from, CHK_WRITE | CHK_NOACCESS);
  601.     if (status != NFS_OK)
  602.         return ((int) status);
  603.     status = build_path(rqstp, pathbuf_1, &argp->to, CHK_WRITE | CHK_NOACCESS);
  604.     if (status != NFS_OK)
  605.         return ((int) status);
  606.  
  607.     dprintf(D_CALL, "\tpathfrom='%s' pathto='%s'\n", pathbuf, pathbuf_1);
  608.  
  609.     /* Remove any file handle from our cache. */
  610.     fh_remove(pathbuf);
  611.     fh_remove(pathbuf_1);
  612.  
  613.     if (rename(pathbuf, pathbuf_1) != 0)
  614.         return (nfs_errno());
  615.  
  616.     return (NFS_OK);
  617. }
  618.  
  619. /* For now, we disallow hardlinks between different volumes for
  620.  * security reasons. If we tried harder, we might be able to 
  621.  * support them, but I'm not sure if it's worth it...
  622.  */
  623. int nfsd_nfsproc_link_2(argp, rqstp)
  624. linkargs *argp;
  625. struct svc_req    *rqstp;
  626. {
  627.     nfs_mount *mountp1;
  628.     nfsstat status;
  629.     fhcache *fhc;
  630.     char *path;
  631.  
  632.     fhc = auth_fh(rqstp, &(argp->from), &status, CHK_WRITE | CHK_NOACCESS);
  633.     if (fhc == NULL)
  634.         return status;
  635.     mountp1 = nfsmount;
  636.     path = fhc->path;
  637.  
  638.     status = build_path(rqstp, pathbuf_1, &argp->to, CHK_WRITE | CHK_NOACCESS);
  639.     if (status != NFS_OK)
  640.         return ((int) status);
  641.  
  642.     dprintf(D_CALL, "\tpathfrom='%s' pathto='%s'\n", path, pathbuf_1);
  643.  
  644.     if (nfsmount != mountp1) {
  645.         dprintf(D_CALL, "\tdenied link between different exports\n");
  646.         return NFSERR_ACCES;
  647.     }
  648.  
  649.     if (link(path, pathbuf_1) != 0)
  650.         return (nfs_errno());
  651.     return (NFS_OK);
  652. }
  653.  
  654. int nfsd_nfsproc_symlink_2(argp, rqstp)
  655. symlinkargs *argp;
  656. struct svc_req    *rqstp;
  657. {
  658.     nfsstat status;
  659.  
  660.     status = build_path(rqstp, pathbuf, &argp->from, CHK_WRITE | CHK_NOACCESS);
  661.     if (status != NFS_OK)
  662.         return ((int) status);
  663.  
  664.     dprintf(D_CALL, "\tstring='%s' filename='%s'\n", argp->to, pathbuf);
  665.  
  666.     if (symlink(argp->to, pathbuf) != 0)
  667.         return (nfs_errno());
  668.  
  669.     /*
  670.          * NFS version 2 documentation says "On UNIX servers the
  671.      * attributes are never used...". IMHO, utimes and maybe even
  672.      * owner may still matter.
  673.          */
  674. #ifndef ALLOW_SGIDDIR
  675.     argp->attributes.gid = -1;
  676. #endif
  677.     status = setattr(pathbuf, &argp->attributes, NULL, rqstp,
  678.                 SATTR_CHOWN|SATTR_UTIMES);
  679.  
  680.     return status;
  681. }
  682.  
  683. int nfsd_nfsproc_mkdir_2(argp, rqstp)
  684. createargs *argp;
  685. struct svc_req    *rqstp;
  686. {
  687.     nfsstat status;
  688.     struct stat sbuf;
  689.     diropokres *res;
  690.     struct stat *sbp = &sbuf;
  691.  
  692.     status = build_path(rqstp, pathbuf, &argp->where, CHK_WRITE | CHK_NOACCESS);
  693.     if (status != NFS_OK)
  694.         return ((int) status);
  695.  
  696.     dprintf(D_CALL, "\tfullpath='%s'\n", pathbuf);
  697.  
  698.     if (mkdir(pathbuf, argp->attributes.mode) != 0)
  699.         return (nfs_errno());
  700.  
  701.     res = &result.diropres.diropres_u.diropres;
  702.     status = fh_compose(&(argp->where), &(res->file), &sbp, -1, -1);
  703.     if (status != NFS_OK)
  704.         return ((int) status);
  705.  
  706. #ifndef ALLOW_SGIDDIR
  707.     argp->attributes.gid = -1;
  708. #endif
  709.     status = setattr(pathbuf, &argp->attributes, &sbuf, rqstp,
  710.                 SATTR_CHOWN|SATTR_CHMOD|SATTR_UTIMES);
  711.     if (status != NFS_OK)
  712.         return status;
  713.  
  714.     /* Note that the spb buffer is now invalid! */
  715.     status = fh_getattr(&(res->file), &(res->attributes), NULL, rqstp);
  716.     if (status == NFS_OK)
  717.         dprintf(D_CALL, "\tnew_fh = %s\n", fh_pr(&(res->file)));
  718.     return ((int) status);
  719. }
  720.  
  721. int nfsd_nfsproc_rmdir_2(argp, rqstp)
  722. diropargs *argp;
  723. struct svc_req    *rqstp;
  724. {
  725.     nfsstat status;
  726.  
  727.     status = build_path(rqstp, pathbuf, argp, CHK_WRITE | CHK_NOACCESS);
  728.     if (status != NFS_OK)
  729.         return ((int) status);
  730.  
  731.     dprintf(D_CALL, "\tfullpath='%s'\n", pathbuf);
  732.  
  733.     /* Remove that file handle from our cache. */
  734.     fh_remove(pathbuf);
  735.  
  736.     if (rmdir(pathbuf) != 0)
  737.         return (nfs_errno());
  738.  
  739.     return (NFS_OK);
  740. }
  741.  
  742. /* More Mark Shand code. */
  743. static int dpsize(dp)
  744. struct dirent *dp;
  745. {
  746. #define DP_SLOP    16
  747. #define MAX_E_SIZE sizeof(entry) + NAME_MAX + DP_SLOP
  748.     return (sizeof(entry) + NLENGTH(dp) + DP_SLOP);
  749. }
  750.  
  751. int nfsd_nfsproc_readdir_2(argp, rqstp)
  752. readdirargs *argp;
  753. struct svc_req    *rqstp;
  754. {
  755.     static readdirres oldres;
  756.     entry **e;
  757.     long dloc;
  758.     DIR *dirp;
  759.     struct dirent *dp;
  760.     struct stat sbuf;
  761.     int res_size;
  762.     fhcache *h;
  763.     nfsstat status;
  764.     int hideit;
  765.  
  766.     /* Free the previous result, since it has 'malloc'ed strings.  */
  767.     xdr_free((xdrproc_t)xdr_readdirres, (caddr_t) & oldres);
  768.  
  769.     h = auth_fh(rqstp, &(argp->dir), &status, CHK_READ);
  770.     if (h == NULL)
  771.         return status;
  772.     hideit = ((!re_export && (h->flags & FHC_NFSMOUNTED))
  773.             || nfsmount->o.noaccess);
  774.  
  775.     /* This code is from Mark Shand's version */
  776.     errno = 0;
  777.     if (lstat(h->path, &sbuf) < 0 || !(S_ISDIR(sbuf.st_mode)))
  778.         return (NFSERR_NOTDIR);
  779.     if ((dirp = opendir(h->path)) == NULL)
  780.         return ((errno ? nfs_errno() : NFSERR_NAMETOOLONG));
  781.  
  782.     res_size = 0;
  783.     memcpy(&dloc, argp->cookie, sizeof(dloc));
  784.     if (dloc != 0)
  785.         seekdir(dirp, ntohl(dloc));
  786.     e = &(result.readdirres.readdirres_u.reply.entries);
  787.     while (((res_size + MAX_E_SIZE) < argp->count
  788.         || e == &(result.readdirres.readdirres_u.reply.entries))
  789.            && (dp = readdir(dirp)) != NULL) {
  790.         if (hideit && strcmp(dp->d_name, ".") != 0
  791.             && strcmp(dp->d_name, "..") != 0) {
  792.             dp = NULL;
  793.             break;
  794.         }
  795.         *e = (entry *) xmalloc(sizeof(entry));
  796.         (*e)->fileid = pseudo_inode(dp->d_ino, sbuf.st_dev);
  797.         (*e)->name = xmalloc(NLENGTH(dp) + 1);
  798.         strcpy((*e)->name, dp->d_name);
  799.         dloc = htonl(telldir(dirp));
  800.         memcpy(((*e)->cookie), &dloc, sizeof(nfscookie));
  801.         e = &((*e)->nextentry);
  802.         res_size += dpsize(dp);
  803.     }
  804.     *e = NULL;
  805.     result.readdirres.readdirres_u.reply.eof = (dp == NULL);
  806.     closedir(dirp);
  807.     oldres = result.readdirres;
  808.     return (result.readdirres.status);
  809. }
  810.  
  811. /*
  812.  * Only reports free space correctly for the filesystem that the
  813.  * mount point is on.  Actually it will work fine for any file
  814.  * handle (e.g. sub mounts) but the NFS spec calls for root_fh
  815.  * to be used by the client when calling this.
  816.  */
  817. int nfsd_nfsproc_statfs_2(argp, rqstp)
  818. nfs_fh *argp;
  819. struct svc_req    *rqstp;
  820. {
  821.     nfsstat status;
  822.     fhcache *fhc;
  823.     char *path;
  824.     struct fs_usage fs;
  825.  
  826.     fhc = auth_fh(rqstp, argp, &status, CHK_READ | CHK_NOACCESS);
  827.     if (fhc == NULL)
  828.         return status;
  829.     path = fhc->path;
  830.  
  831.     if (get_fs_usage(path, NULL, &fs) < 0)
  832.         return (nfs_errno());
  833.     result.statfsres.status = NFS_OK;
  834.     result.statfsres.statfsres_u.reply.tsize = 8*1024;
  835.     result.statfsres.statfsres_u.reply.bsize = 512;
  836.     result.statfsres.statfsres_u.reply.blocks = fs.fsu_blocks;
  837.     result.statfsres.statfsres_u.reply.bfree = fs.fsu_bfree;
  838.     result.statfsres.statfsres_u.reply.bavail = fs.fsu_bavail;
  839.  
  840.     return (NFS_OK);
  841. }
  842.  
  843. int main(argc, argv)
  844. int argc;
  845. char *argv[];
  846. {
  847.     int c;
  848.     char *auth_file = NULL;
  849.     int foreground = 0;
  850.     int nfsport = 0;
  851. #ifdef MULTIPLE_SERVERS
  852.     int ncopies = 0;
  853. #endif
  854.  
  855.     program_name = argv[0];
  856.  
  857.     /* Parse the command line options and arguments. */
  858.     opterr = 0;
  859.     while ((c = getopt_long(argc, argv, "d:Ff:hnP:prtv", longopts, NULL)) != EOF)
  860.         switch (c) {
  861.         case 'h':
  862.             usage(stdout, 0);
  863.             break;
  864.         case 'd':
  865.             enable_logging(optarg);
  866.             break;
  867.         case 'F':
  868.             foreground = 1;
  869.             break;
  870.         case 'f':
  871.             auth_file = optarg;
  872.             break;
  873.         case 'n':
  874.             allow_non_root = 1;
  875.             break;
  876.         case 'P':
  877.             nfsport = atoi(optarg);
  878.             if (nfsport <= 0) {
  879.                 fprintf(stderr, "nfsd: bad port number: %s\n",
  880.                     optarg);
  881.                 usage(stderr, 1);
  882.             }
  883.             break;
  884.         case 'p':
  885.             promiscuous = 1;
  886.             break;
  887.         case 'r':
  888.             re_export = 1;
  889.             break;
  890.         case 't':
  891.             trace_spoof = 0;
  892.             break;
  893.         case 'v':
  894.             printf("%s\n", version);
  895.             exit(0);
  896.         case 0:
  897.             break;
  898.         case '?':
  899.         default:
  900.             usage(stderr, 1);
  901.         }
  902.  
  903. #ifdef MULTIPLE_SERVERS
  904.     if (optind == argc-1 && isdigit(argv[optind][0])) {
  905.         ncopies = atoi(argv[optind++]) - 1;
  906.         if (ncopies < 0) {
  907.             fprintf(stderr, 
  908.                 "nfsd: illegal number of servers requested: %d\n",
  909.                         ncopies + 1);
  910.             exit (1);
  911.         }
  912.         if (foreground) {
  913.             fprintf(stderr, "nfsd: warning: can run only "
  914.                     "one server in debug mode\n");
  915.             ncopies = 0;
  916.         }
  917.         if (ncopies)
  918.             read_only = 1;
  919.     }
  920. #endif
  921.  
  922.     /* No more arguments allowed. */
  923.     if (optind != argc)
  924.         usage(stderr, 1);
  925.  
  926.     /* Get the default NFS port */
  927.     if (!nfsport) {
  928.         struct servent    *sp;
  929.  
  930.         if (!(sp = getservbyname("nfs", "udp"))) {
  931.             nfsport = NFS_PORT;
  932.         } else {
  933.             nfsport = ntohs(sp->s_port);
  934.         }
  935.     }
  936.  
  937.     /* Initialize RPC stuff */
  938.     rpc_init("nfsd", NFS_PROGRAM, NFS_VERSION, nfs_dispatch,
  939.                 nfsport, NFS_MAXDATA);
  940.  
  941.     /* Force foreground mode when started by inetd */
  942.     if (_rpcpmstart) {
  943.         foreground = 1;
  944.         ncopies = 0;
  945.     }
  946.  
  947.     /* We first fork off a child. */
  948.     if (!foreground) {
  949.         if ((c = fork()) > 0)
  950.             exit(0);
  951.         if (c < 0) {
  952.             fprintf(stderr, "nfsd: cannot fork: %s\n",
  953.                         strerror(errno));
  954.             exit(-1);
  955.         }
  956.         /* Now we remove ourselves from the foreground. */
  957.         close(0);
  958.         close(1);
  959.         close(2);
  960. #ifdef HAVE_SETSID
  961.         setsid();
  962. #else
  963.         {
  964.             int fd;
  965.     
  966.             if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
  967.                 ioctl(fd, TIOCNOTTY, (char *) NULL);
  968.                 close(fd);
  969.             }
  970.         }
  971. #endif
  972.     }
  973.  
  974. #ifdef MULTIPLE_SERVERS
  975.     /* Start multiple copies of the server */
  976.     while (ncopies != 0) {
  977.         if ((c = fork()) < 0) {
  978.             perror("fork");
  979.         } else if (c == 0) {
  980.             ncopies = 0;
  981.         } else {
  982.             ncopies--;
  983.         }
  984.     }
  985. #endif
  986.  
  987.     /* Initialize logging. */
  988.     log_open("nfsd", foreground);
  989.  
  990.     /* Initialize the FH module. */
  991.     fh_init();
  992.  
  993.     /* Initialize the AUTH module. */
  994.     auth_init(auth_file);
  995.  
  996.     /* Enable the LOG toggle with a signal. */
  997.     signal(SIGUSR1, toggle_logging);
  998. #ifdef CALL_PROFILING
  999.     signal(SIGIOT, dump_stats);
  1000. #endif
  1001.     signal(SIGHUP, reinitialize);
  1002.  
  1003.     /* Run the NFS server. */
  1004.     svc_run();
  1005.  
  1006.     dprintf(L_ERROR, "Oh no Mr. Bill... nfs_server() returned!\n");
  1007.     exit(1);
  1008. }
  1009.  
  1010. static void usage(fp, n)
  1011. FILE *fp;
  1012. int n;
  1013. {
  1014.     fprintf(fp,"Usage: %s [-Fhnpv] [-d kind] [-f exports-file] [-P port]\n",
  1015.                         program_name);
  1016.     fprintf(fp,"       [--debug kind] [--help] [--allow-non-root]\n");
  1017.     fprintf(fp,"       [--promiscuous] [--version] [--foreground]\n");
  1018.     fprintf(fp,"       [--exports-file=file] [--port port]\n");
  1019.     exit(n);
  1020. }
  1021.  
  1022. RETSIGTYPE reinitialize(sig)
  1023. int sig;
  1024. {
  1025.     static volatile int    inprogress = 0;
  1026.  
  1027.     signal (SIGHUP, reinitialize);
  1028.     if (_rpcsvcdirty) {
  1029.         need_reinit = 1;
  1030.         return;
  1031.     }
  1032.     if (inprogress++)    /* Probably non-atomic. Yuck */
  1033.         return;
  1034.     fh_flush(1);
  1035.     auth_init(NULL);    /* auth_init saves the exports file name */
  1036.     inprogress = 0;
  1037.     need_reinit = 0;
  1038. }
  1039.  
  1040.